library(edgeR)
library (lattice)
library (snpStats)
library (tidyverse)
library(EnhancedVolcano)
library(VennDiagram)
library(gplots)
library(dplyr)

library(fgsea)
library(data.table)
library(ggplot2)
library(Rcpp)

counts = read.delim('counts_matrix_KO_Control.csv', row.names = 1, sep = ',')
head(counts)
names(counts)
[1] "D0.12.3" "D0.8.1"  "D0.28.3" "D0.12.1" "D0.G.1"  "D0.G.3"  "D0.G.2" 
d0 = DGEList(counts)
d0 = calcNormFactors(d0)
head(d0)
An object of class "DGEList"
$counts
                  D0.12.3 D0.8.1 D0.28.3 D0.12.1 D0.G.1 D0.G.3 D0.G.2
ENSG00000223972.5       2      3       2       4      4      4      3
ENSG00000227232.5     200    136     151     195    199    174    195
ENSG00000278267.1       0      0       0       0      0      0      0
ENSG00000243485.5       0      0       0       0      0      0      0
ENSG00000284332.1       0      0       0       0      0      0      0
ENSG00000237613.2       0      0       0       0      0      0      0

$samples
cutoff = 1
drop = which(apply(cpm(d0), 1, max) < cutoff)
d = d0[-drop,] 
dim(d) # number of genes left
[1] 14354     7
print(d)
An object of class "DGEList"
$counts
                  D0.12.3 D0.8.1 D0.28.3 D0.12.1 D0.G.1 D0.G.3 D0.G.2
ENSG00000227232.5     200    136     151     195    199    174    195
ENSG00000279457.4     284    282     208     225    284    312    228
ENSG00000225972.1    1128    643     802    1167    784    734    965
ENSG00000225630.1    1928   1398    1521    2028   1442   1637   1859
ENSG00000237973.1   13127   9470   10499   14625  10132  11545  12922
14349 more rows ...

$samples
NA
sample_description = read.delim('sample_descriptions_KO_Control.csv', sep = ',')
sample_description
#denoted tb, group treatment and background. fulv.Control or palbo.KO
group_treatment_background=interaction(sample_description$Treatment,sample_description$Background)
print(group_treatment_background)
[1] Pretx.KO      Pretx.KO      Pretx.KO      Pretx.KO      Pretx.Control Pretx.Control Pretx.Control
Levels: Pretx.Control Pretx.KO
plotMDS(d, col = as.numeric(group_treatment_background))




#denoted tdb, group treatment and days and background. fulv.0.control or palbo.16.KO
group_treatment_days_background = interaction(sample_description$Treatment,sample_description$Days,sample_description$Background)
print(group_treatment_days_background)
[1] Pretx.0.KO      Pretx.0.KO      Pretx.0.KO      Pretx.0.KO      Pretx.0.Control Pretx.0.Control Pretx.0.Control
Levels: Pretx.0.Control Pretx.0.KO
plotMDS(d, col = as.numeric(group_treatment_days_background))


#denoted tdg, group treatment and days and guide. fulv.0.12 or palbo.16.G
group_treatment_days_guide = interaction(sample_description$Treatment,sample_description$Days,sample_description$KO_Guide)
print(group_treatment_days_guide)
[1] Pretx.0.12 Pretx.0.8  Pretx.0.28 Pretx.0.12 Pretx.0.G  Pretx.0.G  Pretx.0.G 
Levels: Pretx.0.12 Pretx.0.28 Pretx.0.8 Pretx.0.G
plotMDS(d, col = as.numeric(group_treatment_days_guide))

NA
NA
NA
NA
grouping_tdb = group_treatment_days_background


mm_tdb = model.matrix(~0 + grouping_tdb)
y_tdb = voom(d, mm_tdb, plot = T)


fit_tdb = lmFit(y_tdb,mm_tdb)
head(fit_tdb)
An object of class "MArrayLM"
$coefficients
                  grouping_tdbPretx.0.Control grouping_tdbPretx.0.KO
ENSG00000227232.5                    1.756831               1.581529
ENSG00000279457.4                    2.284249               2.155806
ENSG00000225972.1                    3.874888               4.002993
ENSG00000225630.1                    4.869605               4.916537
ENSG00000237973.1                    7.678326               7.719442
ENSG00000229344.1                    6.304919               6.347772

$stdev.unscaled
                  grouping_tdbPretx.0.Control grouping_tdbPretx.0.KO
ENSG00000227232.5                  0.12280460             0.11190515
ENSG00000279457.4                  0.10390522             0.09382165
ENSG00000225972.1                  0.06337341             0.05251130
ENSG00000225630.1                  0.04837761             0.04134976
ENSG00000237973.1                  0.03181627             0.02748405
ENSG00000229344.1                  0.03663558             0.03156744

$sigma
[1] 1.370034 1.173333 4.041833 3.805404 6.225918 4.988128

$df.residual
[1] 5 5 5 5 5 5

$cov.coefficients
                            grouping_tdbPretx.0.Control grouping_tdbPretx.0.KO
grouping_tdbPretx.0.Control                   0.3333333                   0.00
grouping_tdbPretx.0.KO                        0.0000000                   0.25

$pivot
[1] 1 2

$rank
[1] 2

$Amean
ENSG00000227232.5 ENSG00000279457.4 ENSG00000225972.1 ENSG00000225630.1 ENSG00000237973.1 ENSG00000229344.1 
         1.669985          2.212636          3.965151          4.907124          7.705747          6.335550 

$method
[1] "ls"

$design
  grouping_tdbPretx.0.Control grouping_tdbPretx.0.KO
1                           0                      1
2                           0                      1
3                           0                      1
4                           0                      1
5                           1                      0
6                           1                      0
7                           1                      0
attr(,"assign")
[1] 1 1
attr(,"contrasts")
attr(,"contrasts")$grouping_tdb
[1] "contr.treatment"
print(colnames(coef(fit_tdb)))
[1] "grouping_tdbPretx.0.Control" "grouping_tdbPretx.0.KO"     
contrast_group_ko_c= makeContrasts(grouping_tdbPretx.0.KO - grouping_tdbPretx.0.Control, levels = colnames(coef(fit_tdb)))
#contrast
contrastFunction = function(fit_object, contrast_object){
  tmp = contrasts.fit(fit_object, contrast_object)
  tmp = eBayes(tmp)
  top.table = topTable(tmp, sort.by = 'logFC', n = Inf)
  head(top.table, 50)
  qqunif.plot(top.table$P.Val)
  hist(top.table$P.Val)
  print(paste0('number gene adj.p.val <.05 = ', length(which(top.table$adj.P.Val <.05))))

  df = as.data.frame(top.table)
  
  #replace add genename to esng
  gene_name_df <- read.csv('name_description.csv', sep = ',')

  df$gene_name = gene_name_df$Description[match(row.names(df), gene_name_df$Name)]
  return(df)
}



#qqplot
qqunif.plot<-function(pvalues, 
    should.thin=T, thin.obs.places=2, thin.exp.places=2, 
    xlab=expression(paste("Expected (",-log[10], " p-value)")),
    ylab=expression(paste("Observed (",-log[10], " p-value)")), 
    draw.conf=TRUE, conf.points=1000, conf.col="lightgray", conf.alpha=.05,
    already.transformed=FALSE, pch=20, aspect="iso", prepanel=prepanel.qqunif,
    par.settings=list(superpose.symbol=list(pch=pch)), ...) {
    
    
    #error checking
    if (length(pvalues)==0) stop("pvalue vector is empty, can't draw plot")
    if(!(class(pvalues)=="numeric" || 
        (class(pvalues)=="list" && all(sapply(pvalues, class)=="numeric"))))
        stop("pvalue vector is not numeric, can't draw plot")
    if (any(is.na(unlist(pvalues)))) stop("pvalue vector contains NA values, can't draw plot")
    if (already.transformed==FALSE) {
        if (any(unlist(pvalues)==0)) stop("pvalue vector contains zeros, can't draw plot")
    } else {
        if (any(unlist(pvalues)<0)) stop("-log10 pvalue vector contains negative values, can't draw plot")
    }
    
    
    grp<-NULL
    n<-1
    exp.x<-c()
    if(is.list(pvalues)) {
        nn<-sapply(pvalues, length)
        rs<-cumsum(nn)
        re<-rs-nn+1
        n<-min(nn)
        if (!is.null(names(pvalues))) {
            grp=factor(rep(names(pvalues), nn), levels=names(pvalues))
            names(pvalues)<-NULL
        } else {
            grp=factor(rep(1:length(pvalues), nn))
        }
        pvo<-pvalues
        pvalues<-numeric(sum(nn))
        exp.x<-numeric(sum(nn))
        for(i in 1:length(pvo)) {
            if (!already.transformed) {
                pvalues[rs[i]:re[i]] <- -log10(pvo[[i]])
                exp.x[rs[i]:re[i]] <- -log10((rank(pvo[[i]], ties.method="first")-.5)/nn[i])
            } else {
                pvalues[rs[i]:re[i]] <- pvo[[i]]
                exp.x[rs[i]:re[i]] <- -log10((nn[i]+1-rank(pvo[[i]], ties.method="first")-.5)/(nn[i]+1))
            }
        }
    } else {
        n <- length(pvalues)+1
        if (!already.transformed) {
            exp.x <- -log10((rank(pvalues, ties.method="first")-.5)/n)
            pvalues <- -log10(pvalues)
        } else {
            exp.x <- -log10((n-rank(pvalues, ties.method="first")-.5)/n)
        }
    }


    #this is a helper function to draw the confidence interval
    panel.qqconf<-function(n, conf.points=1000, conf.col="gray", conf.alpha=.05, ...) {
        require(grid)
        conf.points = min(conf.points, n-1);
        mpts<-matrix(nrow=conf.points*2, ncol=2)
            for(i in seq(from=1, to=conf.points)) {
                    mpts[i,1]<- -log10((i-.5)/n)
                    mpts[i,2]<- -log10(qbeta(1-conf.alpha/2, i, n-i))
                    mpts[conf.points*2+1-i,1]<- -log10((i-.5)/n)
                    mpts[conf.points*2+1-i,2]<- -log10(qbeta(conf.alpha/2, i, n-i))
            }
            grid.polygon(x=mpts[,1],y=mpts[,2], gp=gpar(fill=conf.col, lty=0), default.units="native")
        }

    #reduce number of points to plot
    if (should.thin==T) {
        if (!is.null(grp)) {
            thin <- unique(data.frame(pvalues = round(pvalues, thin.obs.places),
                exp.x = round(exp.x, thin.exp.places),
                grp=grp))
            grp = thin$grp
        } else {
            thin <- unique(data.frame(pvalues = round(pvalues, thin.obs.places),
                exp.x = round(exp.x, thin.exp.places)))
        }
        pvalues <- thin$pvalues
        exp.x <- thin$exp.x
    }
    gc()
    
    prepanel.qqunif= function(x,y,...) {
        A = list()
        A$xlim = range(x)*1.02
        A$xlim[1]=0
        A$ylim = range(y)*1.02
        A$ylim[1] = 0
        return(A)
    }

    #draw the plot
    xyplot(pvalues~exp.x, groups=grp, xlab=xlab, ylab=ylab, aspect=aspect,
        prepanel=prepanel, scales=list(axs="i"), pch=pch,
        panel = function(x, y, ...) {
            if (draw.conf) {
                panel.qqconf(n, conf.points=conf.points, 
                    conf.col=conf.col, conf.alpha=conf.alpha)
            };
            panel.xyplot(x,y, ...);
            panel.abline(0,1);
        }, par.settings=par.settings, ...
    )
}
#volcano plot
plotVolcano = function(df, select_lab, title= NULL,keyvals= NULL){
  EnhancedVolcano(df, lab = df$gene_name, selectLab = select_lab, x = 'logFC', y = 'adj.P.Val',xlim = c(min(df[['logFC']], na.rm = TRUE) - .5, max(df[['logFC']], na.rm = TRUE) +
    .5),
  ylim = c(0, max(-log10(df[['adj.P.Val']]), na.rm = TRUE) + .5),FCcutoff = .001,pCutoff = 1, cutoffLineType = 'blank' ,legendPosition = 'right',drawConnectors =TRUE,widthConnectors = 0.3, pointSize = 1.5, labSize = 3.0, maxoverlapsConnectors = 50, title = title,colCustom = keyvals )
}


gsea_res = function(ranked_df_object, pathway_object){
  set.seed(42)
  fgseaRes = fgsea(pathways = pathway_object, stats = ranked_df_object, minSize = 15, maxSize = 500, eps = 0)
  topPathwaysUp = fgseaRes[ES > 0][head(order(pval), n=Inf),]
  topPathwaysDown = fgseaRes[ES < 0][head(order(pval), n=Inf),]
  topPathwaysUp_pathways = fgseaRes[ES > 0][head(order(pval), n=10),pathway]
  topPathwaysDown_pathways = fgseaRes[ES < 0][head(order(pval), n=10),pathway]
  topPathwaysAll = c(topPathwaysUp_pathways, rev(topPathwaysDown_pathways))
  
  new_list = list(topPathwaysUp, topPathwaysDown, topPathwaysAll, fgseaRes)
  return(new_list)
    
}
df_tdb_ko_c = contrastFunction(fit_tdb, contrast_group_ko_c)
[1] "number gene adj.p.val <.05 = 1978"

#remove duplicate gene values (most genes have similar logFC. remove lower logFC. for gene CYB561D2, logFC is .2 and -.0711, for RGS5, logFC is -.1461 and .004213093)
#duplicates= df_tdb_ko_c[duplicated(df_tdb_ko_c$gene_name),]
df_tdb_ko_c = df_tdb_ko_c[!duplicated(df_tdb_ko_c$gene_name),]

#save as csv
#write.csv(df_tdb_ko_c, 'df_tdb_ko_c.csv')

plotVolcano(df = df_tdb_ko_c, select_lab = df_tdb_ko_c$gene_name)
Warning: ggrepel: 14297 unlabeled data points (too many overlaps). Consider increasing max.overlaps

#t statistic for gsea
ranked_df = df_tdb_ko_c
ranked_df = within(ranked_df, rank <- ranked_df$t)
ranked_df = ranked_df[,c('gene_name', 'rank')]
ranked_df = ranked_df %>% arrange(rank)
ranked_df = deframe(ranked_df)




#plotGseaTable(h.all_pathway[topPathways_h_all_df], ranked_df, fgseaRes_h_all_df, gseaParam= 1, colwidths = c(17, 3, 2, 2, 2.5))
#c1 hallmark gene set
h.all_pathway = gmtPathways('h.all.v7.4.symbols.gmt.txt')
results_list = gsea_res(ranked_df, pathway_object = h.all_pathway)
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.01% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
h.all_pathwayUp = results_list[1]
h.all_pathwayDown = results_list[2]
h.all_pathwayAll = results_list[3]
h.all_pathway_fgseaRes = results_list[4]
print(h.all_pathwayUp)
[[1]]
print(h.all_pathwayDown)
[[1]]
#plotGseaTable(h.all_pathway[h.all_pathwayAll, ranked_df, h.all_pathway_fgseaRes, gseaParam= 1, colwidths = c(17, 3, 2, 2, 2.5))
#c2 curated gene sets
c2.all_pathway = gmtPathways('c2.all.v7.4.symbols.gmt.txt')
results_list = gsea_res(ranked_df, pathway_object = c2.all_pathway)
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.01% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
c2.all_pathwayUp = results_list[1]
c2.all_pathwayDown = results_list[2]
c2.all_pathwayAll = results_list[3]
c2.all_pathway_fgseaRes = results_list[4]
print(c2.all_pathwayUp)
[[1]]
print(c2.all_pathwayDown)
[[1]]
NA
#c3 regulatory target transcription factor targets
c3.tft_pathway = gmtPathways('c3.tft.v7.4.symbols.gmt.txt')
results_list = gsea_res(ranked_df, pathway_object = c3.tft_pathway)
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.01% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
c3.tft_pathwayUp = results_list[1]
c3.tft_pathwayDown = results_list[2]
c3.tft_pathwayAll = results_list[3]
c3.tft_pathway_fgseaRes = results_list[4]
print(c3.tft_pathwayUp)
[[1]]
print(c3.tft_pathwayDown)
[[1]]
NA
#c5 gene ontology molecular function
c5.go.mf_pathway = gmtPathways('c5.go.mf.v7.4.symbols.gmt.txt')
results_list = gsea_res(ranked_df, pathway_object = c5.go.mf_pathway)
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.01% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
c5.go.mf_pathwayUp = results_list[1]
c5.go.mf_pathwayDown = results_list[2]
c5.go.mf_pathwayAll = results_list[3]
c5.go.mf_pathway_fgseaRes = results_list[4]
print(c5.go.mf_pathwayUp)
[[1]]
print(c5.go.mf_pathwayDown)
[[1]]
NA
#c6 ongogenic signature genesets
c6.all_pathway = gmtPathways('c6.all.v7.4.symbols.gmt.txt')
results_list = gsea_res(ranked_df, pathway_object = c6.all_pathway)
Warning in preparePathwaysAndStats(pathways, stats, minSize, maxSize, gseaParam,  :
  There are ties in the preranked stats (0.01% of the list).
The order of those tied genes will be arbitrary, which may produce unexpected results.
c6.all_pathwayUp = results_list[1]
c6.all_pathwayDown = results_list[2]
c6.all_pathwayAll = results_list[3]
c6.all_pathway_fgseaRes = results_list[4]
print(c6.all_pathwayUp)
[[1]]
print(c6.all_pathwayDown)
[[1]]
NA
#highlight specific genes in volcano plot
#gene_df<- read.csv("geneset_reg_esr1.txt")
df = df_tdb_ko_c
gene_df = h.all_pathway
df_gene_interest = df[(df$gene_name %in% gene_df$HALLMARK_ESTROGEN_RESPONSE_EARLY),]

#make new column with only labels for values in gene_list. use if gene_lsit is list
df$gene_label_interest = df_gene_interest$gene_name[match(df$gene_name, df_gene_interest$gene_name)]

keyvals = ifelse(is.na(df$gene_label_interest), 'royalblue','red')



names(keyvals)[keyvals == 'red'] <- 'interest'
names(keyvals)[keyvals == 'royalblue'] <- 'notinterest'
  
pointsize = c(ifelse(is.na(df$gene_label_interest),.5, 3))
plotVolcano(df = df, select_lab = df$gene_label_interest, title = 'Hallmark_estrogen_response_early',keyvals = keyvals)
Warning: ggrepel: 143 unlabeled data points (too many overlaps). Consider increasing max.overlaps



EnhancedVolcano(df_gene_interest, lab = df_gene_interest$gene_name, x = 'logFC', y = 'adj.P.Val',FCcutoff = .001,pCutoff = 1, cutoffLineType = 'blank' ,legendPosition = 'right',drawConnectors =FALSE,widthConnectors = 0.3, pointSize = 1.5, labSize = 3.0, maxoverlapsConnectors = 50)
Warning: Ignoring unknown parameters: xlim, ylim

plotEnrichment(h.all_pathway[['HALLMARK_ESTROGEN_RESPONSE_EARLY']],ranked_df) + labs(title = 'HALLMARK_ESTROGEN_RESPONSE_EARLY')

enrichmentplot = function(gsea_pathway, specific_pathway, ranked_dataframe = ranked_df){
  plotEnrichment(gsea_pathway[[specific_pathway]], ranked_dataframe) + labs(title = specific_pathway)
}
# interest_pathway = h.all_pathwayDown[[1]]$pathway
# enrichmentplot(gsea_pathway = h.all_pathway, specific_pathway = interest_pathway, ranked_dataframe = ranked_df)
for (i in 1:10){

  interest_pathway = h.all_pathwayUp[[1]]$pathway[i]
  print(interest_pathway)
  print(enrichmentplot(gsea_pathway = h.all_pathway, specific_pathway = interest_pathway, ranked_dataframe = ranked_df))
}
[1] "HALLMARK_INTERFERON_GAMMA_RESPONSE"
[1] "HALLMARK_INTERFERON_ALPHA_RESPONSE"
[1] "HALLMARK_EPITHELIAL_MESENCHYMAL_TRANSITION"
[1] "HALLMARK_ALLOGRAFT_REJECTION"
[1] "HALLMARK_MYOGENESIS"
[1] "HALLMARK_XENOBIOTIC_METABOLISM"
[1] "HALLMARK_UV_RESPONSE_UP"
[1] "HALLMARK_OXIDATIVE_PHOSPHORYLATION"
[1] "HALLMARK_COMPLEMENT"
[1] "HALLMARK_COAGULATION"

for (i in 1:5){

  interest_pathway = h.all_pathwayDown[[1]]$pathway[i]
  print(interest_pathway)
  print(enrichmentplot(gsea_pathway = h.all_pathway, specific_pathway = interest_pathway, ranked_dataframe = ranked_df))
}
[1] "HALLMARK_ESTROGEN_RESPONSE_EARLY"
[1] "HALLMARK_ESTROGEN_RESPONSE_LATE"
[1] "HALLMARK_G2M_CHECKPOINT"
[1] "HALLMARK_MITOTIC_SPINDLE"
[1] "HALLMARK_ANDROGEN_RESPONSE"

c2_up_down_interest = read.csv('c2_up_down_pathways.csv')


c2_interest_list_Up = c2_up_down_interest$c2.up

for (i in 1:length(c2_interest_list_Up)){

  interest_pathway = c2_interest_list_Up[i]
  print(interest_pathway)
  print(enrichmentplot(gsea_pathway = c2.all_pathway, specific_pathway = interest_pathway, ranked_dataframe = ranked_df))
}
[1] "CHARAFE_BREAST_CANCER_LUMINAL_VS_MESENCHYMAL_DN"
[1] "CHARAFE_BREAST_CANCER_LUMINAL_VS_BASAL_DN"
[1] "LIM_MAMMARY_STEM_CELL_UP"
[1] "BERTUCCI_MEDULLARY_VS_DUCTAL_BREAST_CANCER_UP"
[1] "SCHUETZ_BREAST_CANCER_DUCTAL_INVASIVE_UP"
[1] "STEIN_ESRRA_TARGETS_UP"
[1] "SMID_BREAST_CANCER_NORMAL_LIKE_UP"
[1] "SMID_BREAST_CANCER_LUMINAL_B_DN"
[1] "CHICAS_RB1_TARGETS_CONFLUENT"
[1] "SANSOM_APC_TARGETS_DN"
[1] "WP_NUCLEAR_RECEPTORS_METAPATHWAY"
[1] "STEIN_ESRRA_TARGETS"
[1] "SATO_SILENCED_BY_METHYLATION_IN_PANCREATIC_CANCER_1"
[1] "VERRECCHIA_EARLY_RESPONSE_TO_TGFB1"
[1] "LIM_MAMMARY_LUMINAL_PROGENITOR_UP"
[1] "GOTZMANN_EPITHELIAL_TO_MESENCHYMAL_TRANSITION_UP"
[1] "HELLER_HDAC_TARGETS_SILENCED_BY_METHYLATION_UP"
[1] "HUANG_FOXA2_TARGETS_DN"
[1] "SMID_BREAST_CANCER_BASAL_UP"
[1] "JECHLINGER_EPITHELIAL_TO_MESENCHYMAL_TRANSITION_UP"
[1] "BOWIE_RESPONSE_TO_TAMOXIFEN"
[1] "GOZGIT_ESR1_TARGETS_UP"
[1] "VANTVEER_BREAST_CANCER_ESR1_DN"

c2_interest_list_Down = c2_up_down_interest$c2.down

for (i in 1:length(c2_interest_list_Down)){

  interest_pathway = c2_interest_list_Down[i]
  print(interest_pathway)
  print(enrichmentplot(gsea_pathway = c2.all_pathway, specific_pathway = interest_pathway, ranked_dataframe = ranked_df))
}
[1] "CHARAFE_BREAST_CANCER_LUMINAL_VS_MESENCHYMAL_UP"
[1] "CREIGHTON_ENDOCRINE_THERAPY_RESISTANCE_5"
[1] "CHARAFE_BREAST_CANCER_LUMINAL_VS_BASAL_UP"
[1] "FARMER_BREAST_CANCER_BASAL_VS_LULMINAL"
[1] "MASSARWEH_RESPONSE_TO_ESTRADIOL"
[1] "VANTVEER_BREAST_CANCER_ESR1_UP"
[1] "PUJANA_BRCA_CENTERED_NETWORK"
[1] "MASSARWEH_TAMOXIFEN_RESISTANCE_DN"
[1] "REACTOME_CHROMATIN_MODIFYING_ENZYMES"
[1] "ZHANG_BREAST_CANCER_PROGENITORS_UP"
[1] "DUTERTRE_ESTRADIOL_RESPONSE_24HR_UP"
[1] "FISCHER_G1_S_CELL_CYCLE"
[1] "PUJANA_BRCA2_PCC_NETWORK"
[1] "DOANE_BREAST_CANCER_ESR1_UP"
[1] "MCBRYAN_PUBERTAL_BREAST_4_5WK_UP"
[1] "DUTERTRE_ESTRADIOL_RESPONSE_6HR_DN"
[1] "KONG_E2F3_TARGETS"
[1] "CREIGHTON_ENDOCRINE_THERAPY_RESISTANCE_1"
[1] "REACTOME_HATS_ACETYLATE_HISTONES"
[1] "HOLLERN_EMT_BREAST_TUMOR_DN"
[1] "CREIGHTON_ENDOCRINE_THERAPY_RESISTANCE_4"
[1] "EGUCHI_CELL_CYCLE_RB1_TARGETS"
[1] "REACTOME_HDMS_DEMETHYLATE_HISTONES"

for (i in 1:20){

  interest_pathway = c3.tft_pathwayUp[[1]]$pathway[i]
  print(interest_pathway)
  print(enrichmentplot(gsea_pathway = c3.tft_pathway, specific_pathway = interest_pathway, ranked_dataframe = ranked_df))
}
[1] "NFE2_01"
[1] "GGGNNTTTCC_NFKB_Q6_01"
[1] "NRF2_Q4"
[1] "AP1_Q6_01"
[1] "SF1_Q6"
[1] "AP1_Q4_01"
[1] "AP1_C"
[1] "TGASTMAGC_NFE2_01"
[1] "ISRE_01"
[1] "SREBP1_Q6"
[1] "AP1_Q6"
[1] "E47_01"
[1] "NR0B1_TARGET_GENES"
[1] "TGACCTTG_SF1_Q6"
[1] "BACH2_01"
[1] "IRF_Q6"
[1] "STAT5B_01"
[1] "CCAWWNAAGG_SRF_Q4"
[1] "AP1_01"
[1] "RGAGGAARY_PU1_Q6"

for (i in 1:20){

  interest_pathway = c3.tft_pathwayDown[[1]]$pathway[i]
  print(interest_pathway)
  print(enrichmentplot(gsea_pathway = c3.tft_pathway, specific_pathway = interest_pathway, ranked_dataframe = ranked_df))
}
[1] "HSD17B8_TARGET_GENES"
[1] "SMTTTTGT_UNKNOWN"
[1] "E2F_Q3"
[1] "E2F_Q3_01"
[1] "DMRT1_TARGET_GENES"
[1] "E2F1_Q4_01"
[1] "TGACATY_UNKNOWN"
[1] "TGTTTGY_HNF3_Q6"
[1] "AREB6_04"
[1] "TTANWNANTGGM_UNKNOWN"
[1] "FOXO3_01"
[1] "FOXO1_01"
[1] "E2F1_Q6_01"
[1] "AP3_Q6"
[1] "FAC1_01"
[1] "PITX2_Q2"
[1] "KCCGNSWTTT_UNKNOWN"
[1] "FOXO4_02"
[1] "SRY_01"
[1] "GGATTA_PITX2_Q2"

for (i in 1:20){

  interest_pathway = c5.go.mf_pathwayUp[[1]]$pathway[i]
  print(interest_pathway)
  print(enrichmentplot(gsea_pathway = c5.go.mf_pathway, specific_pathway = interest_pathway, ranked_dataframe = ranked_df))
}
[1] "GOMF_ION_TRANSMEMBRANE_TRANSPORTER_ACTIVITY"
[1] "GOMF_ELECTRON_TRANSFER_ACTIVITY"
[1] "GOMF_PROTEIN_HOMODIMERIZATION_ACTIVITY"
[1] "GOMF_ACTIVE_TRANSMEMBRANE_TRANSPORTER_ACTIVITY"
[1] "GOMF_CALCIUM_ION_BINDING"
[1] "GOMF_MONOCARBOXYLIC_ACID_BINDING"
[1] "GOMF_ANION_TRANSMEMBRANE_TRANSPORTER_ACTIVITY"
[1] "GOMF_PEPTIDE_BINDING"
[1] "GOMF_ACTIVE_ION_TRANSMEMBRANE_TRANSPORTER_ACTIVITY"
[1] "GOMF_AMIDE_BINDING"
[1] "GOMF_CATION_TRANSMEMBRANE_TRANSPORTER_ACTIVITY"
[1] "GOMF_ABC_TYPE_TRANSPORTER_ACTIVITY"
[1] "GOMF_STRUCTURAL_MOLECULE_ACTIVITY"
[1] "GOMF_ORGANIC_ANION_TRANSMEMBRANE_TRANSPORTER_ACTIVITY"
[1] "GOMF_G_PROTEIN_COUPLED_RECEPTOR_BINDING"
[1] "GOMF_MOLECULAR_TRANSDUCER_ACTIVITY"
[1] "GOMF_PASSIVE_TRANSMEMBRANE_TRANSPORTER_ACTIVITY"
[1] "GOMF_SECONDARY_ACTIVE_TRANSMEMBRANE_TRANSPORTER_ACTIVITY"
[1] "GOMF_ENZYME_INHIBITOR_ACTIVITY"
[1] "GOMF_OXIDOREDUCTASE_ACTIVITY_ACTING_ON_NAD_P_H"

for (i in 1:20){

  interest_pathway = c5.go.mf_pathwayDown[[1]]$pathway[i]
  print(interest_pathway)
  print(enrichmentplot(gsea_pathway = c5.go.mf_pathway, specific_pathway = interest_pathway, ranked_dataframe = ranked_df))
}
[1] "GOMF_DNA_BINDING_TRANSCRIPTION_ACTIVATOR_ACTIVITY"
[1] "GOMF_CHROMATIN_BINDING"
[1] "GOMF_DNA_BINDING_TRANSCRIPTION_REPRESSOR_ACTIVITY"
[1] "GOMF_CHROMATIN_DNA_BINDING"
[1] "GOMF_PROTEIN_DEMETHYLASE_ACTIVITY"
[1] "GOMF_MRNA_BINDING"
[1] "GOMF_DNA_BINDING_TRANSCRIPTION_FACTOR_BINDING"
[1] "GOMF_ACTIN_BINDING"
[1] "GOMF_NUCLEOSOME_BINDING"
[1] "GOMF_DNA_SECONDARY_STRUCTURE_BINDING"
[1] "GOMF_LYS48_SPECIFIC_DEUBIQUITINASE_ACTIVITY"
[1] "GOMF_FOUR_WAY_JUNCTION_DNA_BINDING"
[1] "GOMF_CYTOKINE_RECEPTOR_ACTIVITY"
[1] "GOMF_RNA_POLYMERASE_CORE_ENZYME_BINDING"
[1] "GOMF_DEMETHYLASE_ACTIVITY"
[1] "GOMF_TRANSCRIPTION_COREGULATOR_ACTIVITY"
[1] "GOMF_HISTONE_LYSINE_N_METHYLTRANSFERASE_ACTIVITY"
[1] "GOMF_RNA_POLYMERASE_II_SPECIFIC_DNA_BINDING_TRANSCRIPTION_FACTOR_BINDING"
[1] "GOMF_IMMUNE_RECEPTOR_ACTIVITY"
[1] "GOMF_PEPTIDE_HORMONE_BINDING"

for (i in 1:20){

  interest_pathway = c6.all_pathwayUp[[1]]$pathway[i]
  print(interest_pathway)
  print(enrichmentplot(gsea_pathway = c6.all_pathway, specific_pathway = interest_pathway, ranked_dataframe = ranked_df))
}
[1] "LTE2_UP.V1_DN"
[1] "RAF_UP.V1_UP"
[1] "KRAS.DF.V1_UP"
[1] "VEGF_A_UP.V1_UP"
[1] "EGFR_UP.V1_UP"
[1] "PGF_UP.V1_DN"
[1] "LEF1_UP.V1_UP"
[1] "NFE2L2.V2"
[1] "PTEN_DN.V1_DN"
[1] "PRC2_EZH2_UP.V1_UP"
[1] "KRAS.600.LUNG.BREAST_UP.V1_UP"
[1] "KRAS.LUNG.BREAST_UP.V1_UP"
[1] "BMI1_DN.V1_UP"
[1] "MEK_UP.V1_UP"
[1] "MEL18_DN.V1_UP"
[1] "JNK_DN.V1_DN"
[1] "ATF2_S_UP.V1_DN"
[1] "KRAS.LUNG_UP.V1_UP"
[1] "MTOR_UP.N4.V1_UP"
[1] "KRAS.600_UP.V1_UP"

for (i in 1:20){

  interest_pathway = c6.all_pathwayDown[[1]]$pathway[i]
  print(interest_pathway)
  print(enrichmentplot(gsea_pathway = c6.all_pathway, specific_pathway = interest_pathway, ranked_dataframe = ranked_df))
}
[1] "RAF_UP.V1_DN"
[1] "P53_DN.V1_UP"
[1] "STK33_NOMO_DN"
[1] "ESC_V6.5_UP_LATE.V1_UP"
[1] "STK33_NOMO_UP"
[1] "PRC1_BMI_UP.V1_UP"
[1] "JAK2_DN.V1_DN"
[1] "PDGF_UP.V1_DN"
[1] "LEF1_UP.V1_DN"
[1] "EGFR_UP.V1_DN"
[1] "STK33_UP"
[1] "GCNP_SHH_UP_EARLY.V1_UP"
[1] "MTOR_UP.N4.V1_DN"
[1] "TBK1.DF_DN"
[1] "CAHOY_ASTROCYTIC"
[1] "BCAT.100_UP.V1_DN"
[1] "PTEN_DN.V2_DN"
[1] "ESC_V6.5_UP_EARLY.V1_UP"
[1] "TGFB_UP.V1_DN"
[1] "SINGH_KRAS_DEPENDENCY_SIGNATURE"

LS0tCnRpdGxlOiAiQW5hbHlzaXMgb25seSBLTyBDb250cm9sIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgoKCmBgYHtyfQpsaWJyYXJ5KGVkZ2VSKQpsaWJyYXJ5IChsYXR0aWNlKQpsaWJyYXJ5IChzbnBTdGF0cykKbGlicmFyeSAodGlkeXZlcnNlKQpsaWJyYXJ5KEVuaGFuY2VkVm9sY2FubykKbGlicmFyeShWZW5uRGlhZ3JhbSkKbGlicmFyeShncGxvdHMpCmxpYnJhcnkoZHBseXIpCgpsaWJyYXJ5KGZnc2VhKQpsaWJyYXJ5KGRhdGEudGFibGUpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShSY3BwKQoKY291bnRzID0gcmVhZC5kZWxpbSgnY291bnRzX21hdHJpeF9LT19Db250cm9sLmNzdicsIHJvdy5uYW1lcyA9IDEsIHNlcCA9ICcsJykKaGVhZChjb3VudHMpCm5hbWVzKGNvdW50cykKYGBgCmBgYHtyfQpkMCA9IERHRUxpc3QoY291bnRzKQpkMCA9IGNhbGNOb3JtRmFjdG9ycyhkMCkKaGVhZChkMCkKCmN1dG9mZiA9IDEKZHJvcCA9IHdoaWNoKGFwcGx5KGNwbShkMCksIDEsIG1heCkgPCBjdXRvZmYpCmQgPSBkMFstZHJvcCxdIApkaW0oZCkgIyBudW1iZXIgb2YgZ2VuZXMgbGVmdApwcmludChkKQpgYGAKYGBge3J9CnNhbXBsZV9kZXNjcmlwdGlvbiA9IHJlYWQuZGVsaW0oJ3NhbXBsZV9kZXNjcmlwdGlvbnNfS09fQ29udHJvbC5jc3YnLCBzZXAgPSAnLCcpCnNhbXBsZV9kZXNjcmlwdGlvbgpgYGAKYGBge3J9CiNkZW5vdGVkIHRiLCBncm91cCB0cmVhdG1lbnQgYW5kIGJhY2tncm91bmQuIGZ1bHYuQ29udHJvbCBvciBwYWxiby5LTwpncm91cF90cmVhdG1lbnRfYmFja2dyb3VuZD1pbnRlcmFjdGlvbihzYW1wbGVfZGVzY3JpcHRpb24kVHJlYXRtZW50LHNhbXBsZV9kZXNjcmlwdGlvbiRCYWNrZ3JvdW5kKQpwcmludChncm91cF90cmVhdG1lbnRfYmFja2dyb3VuZCkKCnBsb3RNRFMoZCwgY29sID0gYXMubnVtZXJpYyhncm91cF90cmVhdG1lbnRfYmFja2dyb3VuZCkpCgoKCiNkZW5vdGVkIHRkYiwgZ3JvdXAgdHJlYXRtZW50IGFuZCBkYXlzIGFuZCBiYWNrZ3JvdW5kLiBmdWx2LjAuY29udHJvbCBvciBwYWxiby4xNi5LTwpncm91cF90cmVhdG1lbnRfZGF5c19iYWNrZ3JvdW5kID0gaW50ZXJhY3Rpb24oc2FtcGxlX2Rlc2NyaXB0aW9uJFRyZWF0bWVudCxzYW1wbGVfZGVzY3JpcHRpb24kRGF5cyxzYW1wbGVfZGVzY3JpcHRpb24kQmFja2dyb3VuZCkKcHJpbnQoZ3JvdXBfdHJlYXRtZW50X2RheXNfYmFja2dyb3VuZCkKCnBsb3RNRFMoZCwgY29sID0gYXMubnVtZXJpYyhncm91cF90cmVhdG1lbnRfZGF5c19iYWNrZ3JvdW5kKSkKCiNkZW5vdGVkIHRkZywgZ3JvdXAgdHJlYXRtZW50IGFuZCBkYXlzIGFuZCBndWlkZS4gZnVsdi4wLjEyIG9yIHBhbGJvLjE2LkcKZ3JvdXBfdHJlYXRtZW50X2RheXNfZ3VpZGUgPSBpbnRlcmFjdGlvbihzYW1wbGVfZGVzY3JpcHRpb24kVHJlYXRtZW50LHNhbXBsZV9kZXNjcmlwdGlvbiREYXlzLHNhbXBsZV9kZXNjcmlwdGlvbiRLT19HdWlkZSkKcHJpbnQoZ3JvdXBfdHJlYXRtZW50X2RheXNfZ3VpZGUpCgpwbG90TURTKGQsIGNvbCA9IGFzLm51bWVyaWMoZ3JvdXBfdHJlYXRtZW50X2RheXNfZ3VpZGUpKQoKCgoKYGBgCmBgYHtyfQpncm91cGluZ190ZGIgPSBncm91cF90cmVhdG1lbnRfZGF5c19iYWNrZ3JvdW5kCgoKbW1fdGRiID0gbW9kZWwubWF0cml4KH4wICsgZ3JvdXBpbmdfdGRiKQp5X3RkYiA9IHZvb20oZCwgbW1fdGRiLCBwbG90ID0gVCkKCmZpdF90ZGIgPSBsbUZpdCh5X3RkYixtbV90ZGIpCmhlYWQoZml0X3RkYikKCnByaW50KGNvbG5hbWVzKGNvZWYoZml0X3RkYikpKQpjb250cmFzdF9ncm91cF9rb19jPSBtYWtlQ29udHJhc3RzKGdyb3VwaW5nX3RkYlByZXR4LjAuS08gLSBncm91cGluZ190ZGJQcmV0eC4wLkNvbnRyb2wsIGxldmVscyA9IGNvbG5hbWVzKGNvZWYoZml0X3RkYikpKQoKCgpgYGAKYGBge3J9CiNjb250cmFzdApjb250cmFzdEZ1bmN0aW9uID0gZnVuY3Rpb24oZml0X29iamVjdCwgY29udHJhc3Rfb2JqZWN0KXsKICB0bXAgPSBjb250cmFzdHMuZml0KGZpdF9vYmplY3QsIGNvbnRyYXN0X29iamVjdCkKICB0bXAgPSBlQmF5ZXModG1wKQogIHRvcC50YWJsZSA9IHRvcFRhYmxlKHRtcCwgc29ydC5ieSA9ICdsb2dGQycsIG4gPSBJbmYpCiAgaGVhZCh0b3AudGFibGUsIDUwKQogIHFxdW5pZi5wbG90KHRvcC50YWJsZSRQLlZhbCkKICBoaXN0KHRvcC50YWJsZSRQLlZhbCkKICBwcmludChwYXN0ZTAoJ251bWJlciBnZW5lIGFkai5wLnZhbCA8LjA1ID0gJywgbGVuZ3RoKHdoaWNoKHRvcC50YWJsZSRhZGouUC5WYWwgPC4wNSkpKSkKCiAgZGYgPSBhcy5kYXRhLmZyYW1lKHRvcC50YWJsZSkKICAKICAjcmVwbGFjZSBhZGQgZ2VuZW5hbWUgdG8gZXNuZwogIGdlbmVfbmFtZV9kZiA8LSByZWFkLmNzdignbmFtZV9kZXNjcmlwdGlvbi5jc3YnLCBzZXAgPSAnLCcpCgogIGRmJGdlbmVfbmFtZSA9IGdlbmVfbmFtZV9kZiREZXNjcmlwdGlvblttYXRjaChyb3cubmFtZXMoZGYpLCBnZW5lX25hbWVfZGYkTmFtZSldCiAgcmV0dXJuKGRmKQp9CgoKCiNxcXBsb3QKcXF1bmlmLnBsb3Q8LWZ1bmN0aW9uKHB2YWx1ZXMsIAoJc2hvdWxkLnRoaW49VCwgdGhpbi5vYnMucGxhY2VzPTIsIHRoaW4uZXhwLnBsYWNlcz0yLCAKCXhsYWI9ZXhwcmVzc2lvbihwYXN0ZSgiRXhwZWN0ZWQgKCIsLWxvZ1sxMF0sICIgcC12YWx1ZSkiKSksCgl5bGFiPWV4cHJlc3Npb24ocGFzdGUoIk9ic2VydmVkICgiLC1sb2dbMTBdLCAiIHAtdmFsdWUpIikpLCAKCWRyYXcuY29uZj1UUlVFLCBjb25mLnBvaW50cz0xMDAwLCBjb25mLmNvbD0ibGlnaHRncmF5IiwgY29uZi5hbHBoYT0uMDUsCglhbHJlYWR5LnRyYW5zZm9ybWVkPUZBTFNFLCBwY2g9MjAsIGFzcGVjdD0iaXNvIiwgcHJlcGFuZWw9cHJlcGFuZWwucXF1bmlmLAoJcGFyLnNldHRpbmdzPWxpc3Qoc3VwZXJwb3NlLnN5bWJvbD1saXN0KHBjaD1wY2gpKSwgLi4uKSB7CgkKCQoJI2Vycm9yIGNoZWNraW5nCglpZiAobGVuZ3RoKHB2YWx1ZXMpPT0wKSBzdG9wKCJwdmFsdWUgdmVjdG9yIGlzIGVtcHR5LCBjYW4ndCBkcmF3IHBsb3QiKQoJaWYoIShjbGFzcyhwdmFsdWVzKT09Im51bWVyaWMiIHx8IAoJCShjbGFzcyhwdmFsdWVzKT09Imxpc3QiICYmIGFsbChzYXBwbHkocHZhbHVlcywgY2xhc3MpPT0ibnVtZXJpYyIpKSkpCgkJc3RvcCgicHZhbHVlIHZlY3RvciBpcyBub3QgbnVtZXJpYywgY2FuJ3QgZHJhdyBwbG90IikKCWlmIChhbnkoaXMubmEodW5saXN0KHB2YWx1ZXMpKSkpIHN0b3AoInB2YWx1ZSB2ZWN0b3IgY29udGFpbnMgTkEgdmFsdWVzLCBjYW4ndCBkcmF3IHBsb3QiKQoJaWYgKGFscmVhZHkudHJhbnNmb3JtZWQ9PUZBTFNFKSB7CgkJaWYgKGFueSh1bmxpc3QocHZhbHVlcyk9PTApKSBzdG9wKCJwdmFsdWUgdmVjdG9yIGNvbnRhaW5zIHplcm9zLCBjYW4ndCBkcmF3IHBsb3QiKQoJfSBlbHNlIHsKCQlpZiAoYW55KHVubGlzdChwdmFsdWVzKTwwKSkgc3RvcCgiLWxvZzEwIHB2YWx1ZSB2ZWN0b3IgY29udGFpbnMgbmVnYXRpdmUgdmFsdWVzLCBjYW4ndCBkcmF3IHBsb3QiKQoJfQoJCgkKCWdycDwtTlVMTAoJbjwtMQoJZXhwLng8LWMoKQoJaWYoaXMubGlzdChwdmFsdWVzKSkgewoJCW5uPC1zYXBwbHkocHZhbHVlcywgbGVuZ3RoKQoJCXJzPC1jdW1zdW0obm4pCgkJcmU8LXJzLW5uKzEKCQluPC1taW4obm4pCgkJaWYgKCFpcy5udWxsKG5hbWVzKHB2YWx1ZXMpKSkgewoJCQlncnA9ZmFjdG9yKHJlcChuYW1lcyhwdmFsdWVzKSwgbm4pLCBsZXZlbHM9bmFtZXMocHZhbHVlcykpCgkJCW5hbWVzKHB2YWx1ZXMpPC1OVUxMCgkJfSBlbHNlIHsKCQkJZ3JwPWZhY3RvcihyZXAoMTpsZW5ndGgocHZhbHVlcyksIG5uKSkKCQl9CgkJcHZvPC1wdmFsdWVzCgkJcHZhbHVlczwtbnVtZXJpYyhzdW0obm4pKQoJCWV4cC54PC1udW1lcmljKHN1bShubikpCgkJZm9yKGkgaW4gMTpsZW5ndGgocHZvKSkgewoJCQlpZiAoIWFscmVhZHkudHJhbnNmb3JtZWQpIHsKCQkJCXB2YWx1ZXNbcnNbaV06cmVbaV1dIDwtIC1sb2cxMChwdm9bW2ldXSkKCQkJCWV4cC54W3JzW2ldOnJlW2ldXSA8LSAtbG9nMTAoKHJhbmsocHZvW1tpXV0sIHRpZXMubWV0aG9kPSJmaXJzdCIpLS41KS9ubltpXSkKCQkJfSBlbHNlIHsKCQkJCXB2YWx1ZXNbcnNbaV06cmVbaV1dIDwtIHB2b1tbaV1dCgkJCQlleHAueFtyc1tpXTpyZVtpXV0gPC0gLWxvZzEwKChubltpXSsxLXJhbmsocHZvW1tpXV0sIHRpZXMubWV0aG9kPSJmaXJzdCIpLS41KS8obm5baV0rMSkpCgkJCX0KCQl9Cgl9IGVsc2UgewoJCW4gPC0gbGVuZ3RoKHB2YWx1ZXMpKzEKCQlpZiAoIWFscmVhZHkudHJhbnNmb3JtZWQpIHsKCQkJZXhwLnggPC0gLWxvZzEwKChyYW5rKHB2YWx1ZXMsIHRpZXMubWV0aG9kPSJmaXJzdCIpLS41KS9uKQoJCQlwdmFsdWVzIDwtIC1sb2cxMChwdmFsdWVzKQoJCX0gZWxzZSB7CgkJCWV4cC54IDwtIC1sb2cxMCgobi1yYW5rKHB2YWx1ZXMsIHRpZXMubWV0aG9kPSJmaXJzdCIpLS41KS9uKQoJCX0KCX0KCgoJI3RoaXMgaXMgYSBoZWxwZXIgZnVuY3Rpb24gdG8gZHJhdyB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbAoJcGFuZWwucXFjb25mPC1mdW5jdGlvbihuLCBjb25mLnBvaW50cz0xMDAwLCBjb25mLmNvbD0iZ3JheSIsIGNvbmYuYWxwaGE9LjA1LCAuLi4pIHsKCQlyZXF1aXJlKGdyaWQpCgkJY29uZi5wb2ludHMgPSBtaW4oY29uZi5wb2ludHMsIG4tMSk7CgkJbXB0czwtbWF0cml4KG5yb3c9Y29uZi5wb2ludHMqMiwgbmNvbD0yKQogICAgICAgIAlmb3IoaSBpbiBzZXEoZnJvbT0xLCB0bz1jb25mLnBvaW50cykpIHsKICAgICAgICAgICAgCQltcHRzW2ksMV08LSAtbG9nMTAoKGktLjUpL24pCiAgICAgICAgICAgIAkJbXB0c1tpLDJdPC0gLWxvZzEwKHFiZXRhKDEtY29uZi5hbHBoYS8yLCBpLCBuLWkpKQogICAgICAgICAgICAJCW1wdHNbY29uZi5wb2ludHMqMisxLWksMV08LSAtbG9nMTAoKGktLjUpL24pCiAgICAgICAgICAgIAkJbXB0c1tjb25mLnBvaW50cyoyKzEtaSwyXTwtIC1sb2cxMChxYmV0YShjb25mLmFscGhhLzIsIGksIG4taSkpCiAgICAgICAgCX0KICAgICAgICAJZ3JpZC5wb2x5Z29uKHg9bXB0c1ssMV0seT1tcHRzWywyXSwgZ3A9Z3BhcihmaWxsPWNvbmYuY29sLCBsdHk9MCksIGRlZmF1bHQudW5pdHM9Im5hdGl2ZSIpCiAgICAJfQoKCSNyZWR1Y2UgbnVtYmVyIG9mIHBvaW50cyB0byBwbG90CglpZiAoc2hvdWxkLnRoaW49PVQpIHsKCQlpZiAoIWlzLm51bGwoZ3JwKSkgewoJCQl0aGluIDwtIHVuaXF1ZShkYXRhLmZyYW1lKHB2YWx1ZXMgPSByb3VuZChwdmFsdWVzLCB0aGluLm9icy5wbGFjZXMpLAoJCQkJZXhwLnggPSByb3VuZChleHAueCwgdGhpbi5leHAucGxhY2VzKSwKCQkJCWdycD1ncnApKQoJCQlncnAgPSB0aGluJGdycAoJCX0gZWxzZSB7CgkJCXRoaW4gPC0gdW5pcXVlKGRhdGEuZnJhbWUocHZhbHVlcyA9IHJvdW5kKHB2YWx1ZXMsIHRoaW4ub2JzLnBsYWNlcyksCgkJCQlleHAueCA9IHJvdW5kKGV4cC54LCB0aGluLmV4cC5wbGFjZXMpKSkKCQl9CgkJcHZhbHVlcyA8LSB0aGluJHB2YWx1ZXMKCQlleHAueCA8LSB0aGluJGV4cC54Cgl9CglnYygpCgkKCXByZXBhbmVsLnFxdW5pZj0gZnVuY3Rpb24oeCx5LC4uLikgewoJCUEgPSBsaXN0KCkKCQlBJHhsaW0gPSByYW5nZSh4KSoxLjAyCgkJQSR4bGltWzFdPTAKCQlBJHlsaW0gPSByYW5nZSh5KSoxLjAyCgkJQSR5bGltWzFdID0gMAoJCXJldHVybihBKQoJfQoKCSNkcmF3IHRoZSBwbG90Cgl4eXBsb3QocHZhbHVlc35leHAueCwgZ3JvdXBzPWdycCwgeGxhYj14bGFiLCB5bGFiPXlsYWIsIGFzcGVjdD1hc3BlY3QsCgkJcHJlcGFuZWw9cHJlcGFuZWwsIHNjYWxlcz1saXN0KGF4cz0iaSIpLCBwY2g9cGNoLAoJCXBhbmVsID0gZnVuY3Rpb24oeCwgeSwgLi4uKSB7CgkJCWlmIChkcmF3LmNvbmYpIHsKCQkJCXBhbmVsLnFxY29uZihuLCBjb25mLnBvaW50cz1jb25mLnBvaW50cywgCgkJCQkJY29uZi5jb2w9Y29uZi5jb2wsIGNvbmYuYWxwaGE9Y29uZi5hbHBoYSkKCQkJfTsKCQkJcGFuZWwueHlwbG90KHgseSwgLi4uKTsKCQkJcGFuZWwuYWJsaW5lKDAsMSk7CgkJfSwgcGFyLnNldHRpbmdzPXBhci5zZXR0aW5ncywgLi4uCgkpCn0KCmBgYAoKYGBge3J9CiN2b2xjYW5vIHBsb3QKcGxvdFZvbGNhbm8gPSBmdW5jdGlvbihkZiwgc2VsZWN0X2xhYiwgdGl0bGU9IE5VTEwsa2V5dmFscz0gTlVMTCl7CiAgRW5oYW5jZWRWb2xjYW5vKGRmLCBsYWIgPSBkZiRnZW5lX25hbWUsIHNlbGVjdExhYiA9IHNlbGVjdF9sYWIsIHggPSAnbG9nRkMnLCB5ID0gJ2Fkai5QLlZhbCcseGxpbSA9IGMobWluKGRmW1snbG9nRkMnXV0sIG5hLnJtID0gVFJVRSkgLSAuNSwgbWF4KGRmW1snbG9nRkMnXV0sIG5hLnJtID0gVFJVRSkgKwogICAgLjUpLAogIHlsaW0gPSBjKDAsIG1heCgtbG9nMTAoZGZbWydhZGouUC5WYWwnXV0pLCBuYS5ybSA9IFRSVUUpICsgLjUpLEZDY3V0b2ZmID0gLjAwMSxwQ3V0b2ZmID0gMSwgY3V0b2ZmTGluZVR5cGUgPSAnYmxhbmsnICxsZWdlbmRQb3NpdGlvbiA9ICdyaWdodCcsZHJhd0Nvbm5lY3RvcnMgPVRSVUUsd2lkdGhDb25uZWN0b3JzID0gMC4zLCBwb2ludFNpemUgPSAxLjUsIGxhYlNpemUgPSAzLjAsIG1heG92ZXJsYXBzQ29ubmVjdG9ycyA9IDUwLCB0aXRsZSA9IHRpdGxlLGNvbEN1c3RvbSA9IGtleXZhbHMgKQp9CgoKZ3NlYV9yZXMgPSBmdW5jdGlvbihyYW5rZWRfZGZfb2JqZWN0LCBwYXRod2F5X29iamVjdCl7CiAgc2V0LnNlZWQoNDIpCiAgZmdzZWFSZXMgPSBmZ3NlYShwYXRod2F5cyA9IHBhdGh3YXlfb2JqZWN0LCBzdGF0cyA9IHJhbmtlZF9kZl9vYmplY3QsIG1pblNpemUgPSAxNSwgbWF4U2l6ZSA9IDUwMCwgZXBzID0gMCkKICB0b3BQYXRod2F5c1VwID0gZmdzZWFSZXNbRVMgPiAwXVtoZWFkKG9yZGVyKHB2YWwpLCBuPUluZiksXQogIHRvcFBhdGh3YXlzRG93biA9IGZnc2VhUmVzW0VTIDwgMF1baGVhZChvcmRlcihwdmFsKSwgbj1JbmYpLF0KICB0b3BQYXRod2F5c1VwX3BhdGh3YXlzID0gZmdzZWFSZXNbRVMgPiAwXVtoZWFkKG9yZGVyKHB2YWwpLCBuPTEwKSxwYXRod2F5XQogIHRvcFBhdGh3YXlzRG93bl9wYXRod2F5cyA9IGZnc2VhUmVzW0VTIDwgMF1baGVhZChvcmRlcihwdmFsKSwgbj0xMCkscGF0aHdheV0KICB0b3BQYXRod2F5c0FsbCA9IGModG9wUGF0aHdheXNVcF9wYXRod2F5cywgcmV2KHRvcFBhdGh3YXlzRG93bl9wYXRod2F5cykpCiAgCiAgbmV3X2xpc3QgPSBsaXN0KHRvcFBhdGh3YXlzVXAsIHRvcFBhdGh3YXlzRG93biwgdG9wUGF0aHdheXNBbGwsIGZnc2VhUmVzKQogIHJldHVybihuZXdfbGlzdCkKICAgIAp9CmBgYAoKYGBge3J9CmRmX3RkYl9rb19jID0gY29udHJhc3RGdW5jdGlvbihmaXRfdGRiLCBjb250cmFzdF9ncm91cF9rb19jKQpgYGAKCmBgYHtyfQojcmVtb3ZlIGR1cGxpY2F0ZSBnZW5lIHZhbHVlcyAobW9zdCBnZW5lcyBoYXZlIHNpbWlsYXIgbG9nRkMuIHJlbW92ZSBsb3dlciBsb2dGQy4gZm9yIGdlbmUgQ1lCNTYxRDIsIGxvZ0ZDIGlzIC4yIGFuZCAtLjA3MTEsIGZvciBSR1M1LCBsb2dGQyBpcyAtLjE0NjEgYW5kIC4wMDQyMTMwOTMpCiNkdXBsaWNhdGVzPSBkZl90ZGJfa29fY1tkdXBsaWNhdGVkKGRmX3RkYl9rb19jJGdlbmVfbmFtZSksXQpkZl90ZGJfa29fYyA9IGRmX3RkYl9rb19jWyFkdXBsaWNhdGVkKGRmX3RkYl9rb19jJGdlbmVfbmFtZSksXQoKI3NhdmUgYXMgY3N2CiN3cml0ZS5jc3YoZGZfdGRiX2tvX2MsICdkZl90ZGJfa29fYy5jc3YnKQoKcGxvdFZvbGNhbm8oZGYgPSBkZl90ZGJfa29fYywgc2VsZWN0X2xhYiA9IGRmX3RkYl9rb19jJGdlbmVfbmFtZSkKCgpgYGAKYGBge3J9CiN0IHN0YXRpc3RpYyBmb3IgZ3NlYQpyYW5rZWRfZGYgPSBkZl90ZGJfa29fYwpyYW5rZWRfZGYgPSB3aXRoaW4ocmFua2VkX2RmLCByYW5rIDwtIHJhbmtlZF9kZiR0KQpyYW5rZWRfZGYgPSByYW5rZWRfZGZbLGMoJ2dlbmVfbmFtZScsICdyYW5rJyldCnJhbmtlZF9kZiA9IHJhbmtlZF9kZiAlPiUgYXJyYW5nZShyYW5rKQpyYW5rZWRfZGYgPSBkZWZyYW1lKHJhbmtlZF9kZikKCgoKCiNwbG90R3NlYVRhYmxlKGguYWxsX3BhdGh3YXlbdG9wUGF0aHdheXNfaF9hbGxfZGZdLCByYW5rZWRfZGYsIGZnc2VhUmVzX2hfYWxsX2RmLCBnc2VhUGFyYW09IDEsIGNvbHdpZHRocyA9IGMoMTcsIDMsIDIsIDIsIDIuNSkpCgoKYGBgCgpgYGB7cn0KI2MxIGhhbGxtYXJrIGdlbmUgc2V0CmguYWxsX3BhdGh3YXkgPSBnbXRQYXRod2F5cygnaC5hbGwudjcuNC5zeW1ib2xzLmdtdC50eHQnKQpyZXN1bHRzX2xpc3QgPSBnc2VhX3JlcyhyYW5rZWRfZGYsIHBhdGh3YXlfb2JqZWN0ID0gaC5hbGxfcGF0aHdheSkKaC5hbGxfcGF0aHdheVVwID0gcmVzdWx0c19saXN0WzFdCmguYWxsX3BhdGh3YXlEb3duID0gcmVzdWx0c19saXN0WzJdCmguYWxsX3BhdGh3YXlBbGwgPSByZXN1bHRzX2xpc3RbM10KaC5hbGxfcGF0aHdheV9mZ3NlYVJlcyA9IHJlc3VsdHNfbGlzdFs0XQpwcmludChoLmFsbF9wYXRod2F5VXApCnByaW50KGguYWxsX3BhdGh3YXlEb3duKQojcGxvdEdzZWFUYWJsZShoLmFsbF9wYXRod2F5W2guYWxsX3BhdGh3YXlBbGwsIHJhbmtlZF9kZiwgaC5hbGxfcGF0aHdheV9mZ3NlYVJlcywgZ3NlYVBhcmFtPSAxLCBjb2x3aWR0aHMgPSBjKDE3LCAzLCAyLCAyLCAyLjUpKQpgYGAKCmBgYHtyfQojYzIgY3VyYXRlZCBnZW5lIHNldHMKYzIuYWxsX3BhdGh3YXkgPSBnbXRQYXRod2F5cygnYzIuYWxsLnY3LjQuc3ltYm9scy5nbXQudHh0JykKcmVzdWx0c19saXN0ID0gZ3NlYV9yZXMocmFua2VkX2RmLCBwYXRod2F5X29iamVjdCA9IGMyLmFsbF9wYXRod2F5KQpjMi5hbGxfcGF0aHdheVVwID0gcmVzdWx0c19saXN0WzFdCmMyLmFsbF9wYXRod2F5RG93biA9IHJlc3VsdHNfbGlzdFsyXQpjMi5hbGxfcGF0aHdheUFsbCA9IHJlc3VsdHNfbGlzdFszXQpjMi5hbGxfcGF0aHdheV9mZ3NlYVJlcyA9IHJlc3VsdHNfbGlzdFs0XQpwcmludChjMi5hbGxfcGF0aHdheVVwKQpwcmludChjMi5hbGxfcGF0aHdheURvd24pCmBgYApgYGB7cn0KI2MzIHJlZ3VsYXRvcnkgdGFyZ2V0IHRyYW5zY3JpcHRpb24gZmFjdG9yIHRhcmdldHMKYzMudGZ0X3BhdGh3YXkgPSBnbXRQYXRod2F5cygnYzMudGZ0LnY3LjQuc3ltYm9scy5nbXQudHh0JykKcmVzdWx0c19saXN0ID0gZ3NlYV9yZXMocmFua2VkX2RmLCBwYXRod2F5X29iamVjdCA9IGMzLnRmdF9wYXRod2F5KQpjMy50ZnRfcGF0aHdheVVwID0gcmVzdWx0c19saXN0WzFdCmMzLnRmdF9wYXRod2F5RG93biA9IHJlc3VsdHNfbGlzdFsyXQpjMy50ZnRfcGF0aHdheUFsbCA9IHJlc3VsdHNfbGlzdFszXQpjMy50ZnRfcGF0aHdheV9mZ3NlYVJlcyA9IHJlc3VsdHNfbGlzdFs0XQpwcmludChjMy50ZnRfcGF0aHdheVVwKQpwcmludChjMy50ZnRfcGF0aHdheURvd24pCmBgYApgYGB7cn0KI2M1IGdlbmUgb250b2xvZ3kgbW9sZWN1bGFyIGZ1bmN0aW9uCmM1LmdvLm1mX3BhdGh3YXkgPSBnbXRQYXRod2F5cygnYzUuZ28ubWYudjcuNC5zeW1ib2xzLmdtdC50eHQnKQpyZXN1bHRzX2xpc3QgPSBnc2VhX3JlcyhyYW5rZWRfZGYsIHBhdGh3YXlfb2JqZWN0ID0gYzUuZ28ubWZfcGF0aHdheSkKYzUuZ28ubWZfcGF0aHdheVVwID0gcmVzdWx0c19saXN0WzFdCmM1LmdvLm1mX3BhdGh3YXlEb3duID0gcmVzdWx0c19saXN0WzJdCmM1LmdvLm1mX3BhdGh3YXlBbGwgPSByZXN1bHRzX2xpc3RbM10KYzUuZ28ubWZfcGF0aHdheV9mZ3NlYVJlcyA9IHJlc3VsdHNfbGlzdFs0XQpwcmludChjNS5nby5tZl9wYXRod2F5VXApCnByaW50KGM1LmdvLm1mX3BhdGh3YXlEb3duKQpgYGAKYGBge3J9CiNjNiBvbmdvZ2VuaWMgc2lnbmF0dXJlIGdlbmVzZXRzCmM2LmFsbF9wYXRod2F5ID0gZ210UGF0aHdheXMoJ2M2LmFsbC52Ny40LnN5bWJvbHMuZ210LnR4dCcpCnJlc3VsdHNfbGlzdCA9IGdzZWFfcmVzKHJhbmtlZF9kZiwgcGF0aHdheV9vYmplY3QgPSBjNi5hbGxfcGF0aHdheSkKYzYuYWxsX3BhdGh3YXlVcCA9IHJlc3VsdHNfbGlzdFsxXQpjNi5hbGxfcGF0aHdheURvd24gPSByZXN1bHRzX2xpc3RbMl0KYzYuYWxsX3BhdGh3YXlBbGwgPSByZXN1bHRzX2xpc3RbM10KYzYuYWxsX3BhdGh3YXlfZmdzZWFSZXMgPSByZXN1bHRzX2xpc3RbNF0KcHJpbnQoYzYuYWxsX3BhdGh3YXlVcCkKcHJpbnQoYzYuYWxsX3BhdGh3YXlEb3duKQpgYGAKCmBgYHtyfQojaGlnaGxpZ2h0IHNwZWNpZmljIGdlbmVzIGluIHZvbGNhbm8gcGxvdAojZ2VuZV9kZjwtIHJlYWQuY3N2KCJnZW5lc2V0X3JlZ19lc3IxLnR4dCIpCmRmID0gZGZfdGRiX2tvX2MKZ2VuZV9kZiA9IGguYWxsX3BhdGh3YXkKZGZfZ2VuZV9pbnRlcmVzdCA9IGRmWyhkZiRnZW5lX25hbWUgJWluJSBnZW5lX2RmJEhBTExNQVJLX0VTVFJPR0VOX1JFU1BPTlNFX0VBUkxZKSxdCgojbWFrZSBuZXcgY29sdW1uIHdpdGggb25seSBsYWJlbHMgZm9yIHZhbHVlcyBpbiBnZW5lX2xpc3QuIHVzZSBpZiBnZW5lX2xzaXQgaXMgbGlzdApkZiRnZW5lX2xhYmVsX2ludGVyZXN0ID0gZGZfZ2VuZV9pbnRlcmVzdCRnZW5lX25hbWVbbWF0Y2goZGYkZ2VuZV9uYW1lLCBkZl9nZW5lX2ludGVyZXN0JGdlbmVfbmFtZSldCgprZXl2YWxzID0gaWZlbHNlKGlzLm5hKGRmJGdlbmVfbGFiZWxfaW50ZXJlc3QpLCAncm95YWxibHVlJywncmVkJykKCgoKbmFtZXMoa2V5dmFscylba2V5dmFscyA9PSAncmVkJ10gPC0gJ2ludGVyZXN0JwpuYW1lcyhrZXl2YWxzKVtrZXl2YWxzID09ICdyb3lhbGJsdWUnXSA8LSAnbm90aW50ZXJlc3QnCiAgCnBvaW50c2l6ZSA9IGMoaWZlbHNlKGlzLm5hKGRmJGdlbmVfbGFiZWxfaW50ZXJlc3QpLC41LCAzKSkKcGxvdFZvbGNhbm8oZGYgPSBkZiwgc2VsZWN0X2xhYiA9IGRmJGdlbmVfbGFiZWxfaW50ZXJlc3QsIHRpdGxlID0gJ0hhbGxtYXJrX2VzdHJvZ2VuX3Jlc3BvbnNlX2Vhcmx5JyxrZXl2YWxzID0ga2V5dmFscykKCmBgYAoKYGBge3J9CgoKRW5oYW5jZWRWb2xjYW5vKGRmX2dlbmVfaW50ZXJlc3QsIGxhYiA9IGRmX2dlbmVfaW50ZXJlc3QkZ2VuZV9uYW1lLCB4ID0gJ2xvZ0ZDJywgeSA9ICdhZGouUC5WYWwnLEZDY3V0b2ZmID0gLjAwMSxwQ3V0b2ZmID0gMSwgY3V0b2ZmTGluZVR5cGUgPSAnYmxhbmsnICxsZWdlbmRQb3NpdGlvbiA9ICdyaWdodCcsZHJhd0Nvbm5lY3RvcnMgPUZBTFNFLHdpZHRoQ29ubmVjdG9ycyA9IDAuMywgcG9pbnRTaXplID0gMS41LCBsYWJTaXplID0gMy4wLCBtYXhvdmVybGFwc0Nvbm5lY3RvcnMgPSA1MCkKYGBgCmBgYHtyfQpwbG90RW5yaWNobWVudChoLmFsbF9wYXRod2F5W1snSEFMTE1BUktfRVNUUk9HRU5fUkVTUE9OU0VfRUFSTFknXV0scmFua2VkX2RmKSArIGxhYnModGl0bGUgPSAnSEFMTE1BUktfRVNUUk9HRU5fUkVTUE9OU0VfRUFSTFknKQpgYGAKCmBgYHtyfQplbnJpY2htZW50cGxvdCA9IGZ1bmN0aW9uKGdzZWFfcGF0aHdheSwgc3BlY2lmaWNfcGF0aHdheSwgcmFua2VkX2RhdGFmcmFtZSA9IHJhbmtlZF9kZil7CiAgcGxvdEVucmljaG1lbnQoZ3NlYV9wYXRod2F5W1tzcGVjaWZpY19wYXRod2F5XV0sIHJhbmtlZF9kYXRhZnJhbWUpICsgbGFicyh0aXRsZSA9IHNwZWNpZmljX3BhdGh3YXkpCn0KCmBgYApgYGB7cn0KIyBpbnRlcmVzdF9wYXRod2F5ID0gaC5hbGxfcGF0aHdheURvd25bWzFdXSRwYXRod2F5WzFdCiMgZW5yaWNobWVudHBsb3QoZ3NlYV9wYXRod2F5ID0gaC5hbGxfcGF0aHdheSwgc3BlY2lmaWNfcGF0aHdheSA9IGludGVyZXN0X3BhdGh3YXksIHJhbmtlZF9kYXRhZnJhbWUgPSByYW5rZWRfZGYpCmBgYAoKYGBge3J9CmZvciAoaSBpbiAxOjEwKXsKCiAgaW50ZXJlc3RfcGF0aHdheSA9IGguYWxsX3BhdGh3YXlVcFtbMV1dJHBhdGh3YXlbaV0KICBwcmludChpbnRlcmVzdF9wYXRod2F5KQogIHByaW50KGVucmljaG1lbnRwbG90KGdzZWFfcGF0aHdheSA9IGguYWxsX3BhdGh3YXksIHNwZWNpZmljX3BhdGh3YXkgPSBpbnRlcmVzdF9wYXRod2F5LCByYW5rZWRfZGF0YWZyYW1lID0gcmFua2VkX2RmKSkKfQpgYGAKCmBgYHtyfQpmb3IgKGkgaW4gMTo1KXsKCiAgaW50ZXJlc3RfcGF0aHdheSA9IGguYWxsX3BhdGh3YXlEb3duW1sxXV0kcGF0aHdheVtpXQogIHByaW50KGludGVyZXN0X3BhdGh3YXkpCiAgcHJpbnQoZW5yaWNobWVudHBsb3QoZ3NlYV9wYXRod2F5ID0gaC5hbGxfcGF0aHdheSwgc3BlY2lmaWNfcGF0aHdheSA9IGludGVyZXN0X3BhdGh3YXksIHJhbmtlZF9kYXRhZnJhbWUgPSByYW5rZWRfZGYpKQp9CmBgYApgYGB7cn0KYzJfdXBfZG93bl9pbnRlcmVzdCA9IHJlYWQuY3N2KCdjMl91cF9kb3duX3BhdGh3YXlzLmNzdicpCgoKYzJfaW50ZXJlc3RfbGlzdF9VcCA9IGMyX3VwX2Rvd25faW50ZXJlc3QkYzIudXAKCmZvciAoaSBpbiAxOmxlbmd0aChjMl9pbnRlcmVzdF9saXN0X1VwKSl7CgogIGludGVyZXN0X3BhdGh3YXkgPSBjMl9pbnRlcmVzdF9saXN0X1VwW2ldCiAgcHJpbnQoaW50ZXJlc3RfcGF0aHdheSkKICBwcmludChlbnJpY2htZW50cGxvdChnc2VhX3BhdGh3YXkgPSBjMi5hbGxfcGF0aHdheSwgc3BlY2lmaWNfcGF0aHdheSA9IGludGVyZXN0X3BhdGh3YXksIHJhbmtlZF9kYXRhZnJhbWUgPSByYW5rZWRfZGYpKQp9CmBgYApgYGB7cn0KYzJfaW50ZXJlc3RfbGlzdF9Eb3duID0gYzJfdXBfZG93bl9pbnRlcmVzdCRjMi5kb3duCgpmb3IgKGkgaW4gMTpsZW5ndGgoYzJfaW50ZXJlc3RfbGlzdF9Eb3duKSl7CgogIGludGVyZXN0X3BhdGh3YXkgPSBjMl9pbnRlcmVzdF9saXN0X0Rvd25baV0KICBwcmludChpbnRlcmVzdF9wYXRod2F5KQogIHByaW50KGVucmljaG1lbnRwbG90KGdzZWFfcGF0aHdheSA9IGMyLmFsbF9wYXRod2F5LCBzcGVjaWZpY19wYXRod2F5ID0gaW50ZXJlc3RfcGF0aHdheSwgcmFua2VkX2RhdGFmcmFtZSA9IHJhbmtlZF9kZikpCn0KYGBgCmBgYHtyfQpmb3IgKGkgaW4gMToyMCl7CgogIGludGVyZXN0X3BhdGh3YXkgPSBjMy50ZnRfcGF0aHdheVVwW1sxXV0kcGF0aHdheVtpXQogIHByaW50KGludGVyZXN0X3BhdGh3YXkpCiAgcHJpbnQoZW5yaWNobWVudHBsb3QoZ3NlYV9wYXRod2F5ID0gYzMudGZ0X3BhdGh3YXksIHNwZWNpZmljX3BhdGh3YXkgPSBpbnRlcmVzdF9wYXRod2F5LCByYW5rZWRfZGF0YWZyYW1lID0gcmFua2VkX2RmKSkKfQpgYGAKCmBgYHtyfQpmb3IgKGkgaW4gMToyMCl7CgogIGludGVyZXN0X3BhdGh3YXkgPSBjMy50ZnRfcGF0aHdheURvd25bWzFdXSRwYXRod2F5W2ldCiAgcHJpbnQoaW50ZXJlc3RfcGF0aHdheSkKICBwcmludChlbnJpY2htZW50cGxvdChnc2VhX3BhdGh3YXkgPSBjMy50ZnRfcGF0aHdheSwgc3BlY2lmaWNfcGF0aHdheSA9IGludGVyZXN0X3BhdGh3YXksIHJhbmtlZF9kYXRhZnJhbWUgPSByYW5rZWRfZGYpKQp9CmBgYApgYGB7cn0KZm9yIChpIGluIDE6MjApewoKICBpbnRlcmVzdF9wYXRod2F5ID0gYzUuZ28ubWZfcGF0aHdheVVwW1sxXV0kcGF0aHdheVtpXQogIHByaW50KGludGVyZXN0X3BhdGh3YXkpCiAgcHJpbnQoZW5yaWNobWVudHBsb3QoZ3NlYV9wYXRod2F5ID0gYzUuZ28ubWZfcGF0aHdheSwgc3BlY2lmaWNfcGF0aHdheSA9IGludGVyZXN0X3BhdGh3YXksIHJhbmtlZF9kYXRhZnJhbWUgPSByYW5rZWRfZGYpKQp9CmBgYApgYGB7cn0KZm9yIChpIGluIDE6MjApewoKICBpbnRlcmVzdF9wYXRod2F5ID0gYzUuZ28ubWZfcGF0aHdheURvd25bWzFdXSRwYXRod2F5W2ldCiAgcHJpbnQoaW50ZXJlc3RfcGF0aHdheSkKICBwcmludChlbnJpY2htZW50cGxvdChnc2VhX3BhdGh3YXkgPSBjNS5nby5tZl9wYXRod2F5LCBzcGVjaWZpY19wYXRod2F5ID0gaW50ZXJlc3RfcGF0aHdheSwgcmFua2VkX2RhdGFmcmFtZSA9IHJhbmtlZF9kZikpCn0KYGBgCmBgYHtyfQpmb3IgKGkgaW4gMToyMCl7CgogIGludGVyZXN0X3BhdGh3YXkgPSBjNi5hbGxfcGF0aHdheVVwW1sxXV0kcGF0aHdheVtpXQogIHByaW50KGludGVyZXN0X3BhdGh3YXkpCiAgcHJpbnQoZW5yaWNobWVudHBsb3QoZ3NlYV9wYXRod2F5ID0gYzYuYWxsX3BhdGh3YXksIHNwZWNpZmljX3BhdGh3YXkgPSBpbnRlcmVzdF9wYXRod2F5LCByYW5rZWRfZGF0YWZyYW1lID0gcmFua2VkX2RmKSkKfQpgYGAKYGBge3J9CmZvciAoaSBpbiAxOjIwKXsKCiAgaW50ZXJlc3RfcGF0aHdheSA9IGM2LmFsbF9wYXRod2F5RG93bltbMV1dJHBhdGh3YXlbaV0KICBwcmludChpbnRlcmVzdF9wYXRod2F5KQogIHByaW50KGVucmljaG1lbnRwbG90KGdzZWFfcGF0aHdheSA9IGM2LmFsbF9wYXRod2F5LCBzcGVjaWZpY19wYXRod2F5ID0gaW50ZXJlc3RfcGF0aHdheSwgcmFua2VkX2RhdGFmcmFtZSA9IHJhbmtlZF9kZikpCn0KYGBgCgo=